﻿#if UNITY_EDITOR
using System.Linq;
using UnityEditor;
#endif
using UnityEngine;
using UnityEngine.AddressableAssets;

namespace SCore.Util
{
    //初始化需要管理的MonoSingleton
    public abstract class ComMonoSingleton<T> : MonoBehaviour where T : Component, IComponent
    {
        private static T s_instance;

        public static T Instance
        {
            get
            {
                if (s_instance == null)
                {
                    s_instance = FindObjectOfType<T>();
                    if (s_instance == null)
                    {
                        GameObject obj = new GameObject();
                        obj.hideFlags = HideFlags.DontSave;
                        GameObject.DontDestroyOnLoad(obj);
                        obj.name = typeof(T).Name;
                        s_instance = obj.GetOrAddComponent<T>();
                    }
                }

                return s_instance;
            }
        }

        public virtual void Init()
        {
            $"{this.GetType().Name} Init".Log();
        }

        public virtual void Clear()
        {
            $"{this.GetType().Name} Clear".Log();
        }
    }

    public abstract class MonoSingleton<T> : MonoBehaviour where T : Component
    {
        private static T s_instance;

        public static T Instance
        {
            get
            {
                if (s_instance == null)
                {
                    s_instance = FindObjectOfType<T>();
                    if (s_instance == null)
                    {
                        GameObject obj = new GameObject();
                        obj.hideFlags = HideFlags.DontSave;
                        GameObject.DontDestroyOnLoad(obj);
                        obj.name = typeof(T).Name;
                        s_instance = obj.GetOrAddComponent<T>();
                    }
                }

                return s_instance;
            }
        }
    }

    public abstract class Singleton<T> : IComponent where T : Singleton<T>, new()
    {
        private static T s_instance = new T();

        public static T Instance
        {
            get { return s_instance; }
        }

        public virtual void Init()
        {
            $"{this.GetType().Name} Init".Log();
        }

        public virtual void Clear()
        {
            $"{this.GetType().Name} Clear".Log();
        }
    }

    public class SingleScriptableObject<T> : ScriptableObject where T : ScriptableObject
    {
        private static readonly string ScriptableObjectPath = typeof(T).Name;

        private static T _instance;

        public static T Instance
        {
            get
            {
#if UNITY_EDITOR
                if (_instance == null)
                {
                    foreach (var config in AssetDatabase.FindAssets($"t:{ScriptableObjectPath.ToLower()}")
                                 .Select(AssetDatabase.GUIDToAssetPath)
                                 .Select(AssetDatabase.LoadAssetAtPath<T>))
                    {
                        _instance = config;
                    }
                }
#else
                if (_instance == null)
                {
                    var handle = Addressables.LoadAssetAsync<T>(ScriptableObjectPath + ".asset");
                    handle.WaitForCompletion();
                    return handle.Result;
                }
#endif

                return _instance;
            }
            set { _instance = value; }
        }
#if UNITY_EDITOR
        public void Save()
        {
            EditorUtility.SetDirty(Instance);
            AssetDatabase.SaveAssetIfDirty(Instance);
            AssetDatabase.Refresh();
        }
#endif
    }
}